package com.cet.qz.unit01.chapter1_2;

import java.util.Objects;

/**
 * @program: algorithm
 * @description:
 * @author: 陈恩涛
 * @create: 2021-03-05 20:56
 **/
public class Qz1_2_16 {

    public static void main(String[] args) {
        Rational rational1 = new Rational(-1, -3);
        Rational rational2 = new Rational(-2, 4);
        Rational sum = rational1.plus(rational2);
        Rational dif = rational1.minus(rational2);
        Rational pro = rational1.times(rational2);
        Rational quotient = rational1.divides(rational2);
        System.out.println("和为："+sum);
        System.out.println("差为："+dif);
        System.out.println("积为："+pro);
        System.out.println("商为："+quotient);

    }
}

class Rational{
    private final long numberator;
    private final long denominator;

    public Rational(long numberator, long denominator) {

        if (denominator == 0) {
            throw new RuntimeException("除数不能为0!");
        }

        // 正负由分子管理
        if (numberator >= 0 && denominator < 0) {
            numberator = -numberator;
            denominator = - denominator;
        }

        if (numberator <= 0 && denominator < 0) {
            numberator = -numberator;
            denominator = - denominator;
        }

        long gcd = gcd(Math.abs(numberator), denominator);

        if (gcd > 1 && gcd < denominator) {
            this.numberator = numberator / gcd;
            this.denominator = denominator / gcd;
        } else {
            this.numberator = numberator;
            this.denominator = denominator;
        }
        assert isLegal(): "分子或分母溢出";
    }

    public Rational plus(Rational b) {

        if (numberator == 0) {
            return b;
        }
        if (b.numberator == 0) {
            return this;
        }

        long sum_den = denominator * b.denominator;

        long sum_num = numberator * b.denominator + b.numberator * denominator;

        Rational sum = new Rational(sum_num, sum_den);

        return sum;
    }

    public Rational minus(Rational b) {

        if (numberator == 0) {
            long minus_num = - b.numberator;
            return new Rational(minus_num, b.denominator);
        }
        if (b.numberator == 0) {
            return this;
        }

        long dif_den = denominator * b.denominator;

        long dif_num = numberator * b.denominator - b.numberator * denominator;

        Rational dif = new Rational(dif_num, dif_den);

        return dif;
    }

    public Rational times(Rational b) {
        if (numberator == 0) {
            return this;
        }

        if (b.numberator == 0) {
            return b;
        }

        long pro_num = numberator * b.numberator;
        long pro_den = denominator * b.denominator;
        return new Rational(pro_num,pro_den);
    }

    public Rational divides(Rational b) {

        if (b.numberator == 0) {
            throw new RuntimeException("除数不能为零！");
        }

        if (numberator == 0) {
            return this;
        }

        long quotient_num = numberator * b.denominator;
        long quotient_den = denominator * b.numberator;

        return new Rational(quotient_num,quotient_den);
    }

    private boolean isLegal() {
        if (numberator > Long.MAX_VALUE || numberator < Long.MIN_VALUE) {
            return false;
        }
        if (denominator > Long.MAX_VALUE || denominator < Long.MIN_VALUE) {
            return false;
        }
        return true;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Rational rational = (Rational) o;
        return numberator == rational.numberator &&
                denominator == rational.denominator;
    }

    @Override
    public int hashCode() {
        return Objects.hash(numberator, denominator);
    }

    /**
     *方法描述： 欧几里得算法
     *
     * @param p
     * @param q
     * @return long
     * @author chenentao
     * @date 2021/3/5 22:10
     */
    private long gcd(long p, long q) {
        if (q == 0) {
            return p;
        }
        long r = p % q;
        return gcd(q, r);
    }

    @Override
    public String toString() {
        return "Rational{" +
                "numberator=" + numberator +
                ", denominator=" + denominator +
                '}';
    }
}
